using System;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;

namespace MagicVoxelParse
{
    public class TMeshBuilder
    {
        public GameObject renderer;
        
        private TVoxelData _voxelData;

        private VoxelParam _voxelParam;
        
        /// <summary>
        /// 表面数据源
        /// </summary>
        private readonly VoxFaceStruct[] _voxFacesSource = new VoxFaceStruct[]
        {
            //左侧面
            new VoxFaceStruct{ faceA = new VoxFaceAB(6,2,0), faceB = new VoxFaceAB(6,0,4)},
            //右侧面
            new VoxFaceStruct{ faceA = new VoxFaceAB(5,1,3), faceB = new VoxFaceAB(5,3,7)},
            //下侧面
            new VoxFaceStruct{ faceA = new VoxFaceAB(5,7,6), faceB = new VoxFaceAB(5,6,4)},
            //上侧面
            new VoxFaceStruct{ faceA = new VoxFaceAB(2,3,1), faceB = new VoxFaceAB(2,1,0)},
            //后侧面
            new VoxFaceStruct{ faceA = new VoxFaceAB(4,0,1), faceB = new VoxFaceAB(4,1,5)},
            //前侧面
            new VoxFaceStruct{ faceA = new VoxFaceAB(7,3,2), faceB = new VoxFaceAB(7,2,6)}
        };
        
        /// <summary>
        /// 顶点数据源
        /// </summary>
        private readonly Vector3[] _voxVerticesSource = new Vector3[]
        {
            //体素上表面坐标，偏移
            new Vector3(-1, 1,-1 ),
            new Vector3( 1, 1,-1 ),
            new Vector3(-1, 1, 1 ),
            new Vector3( 1, 1, 1 ),
            
            //体素下表面坐标，偏移
            new Vector3(-1,-1,-1 ),
            new Vector3( 1,-1,-1 ),
            new Vector3(-1,-1, 1 ),
            new Vector3( 1,-1, 1 )
        };
        
        /// <summary>
        /// 忽略相邻方向的面的对应表
        /// </summary>
        private readonly SixIgnoreFace[] _six = new SixIgnoreFace[]
        {
            //left
            new SixIgnoreFace{ x= -1, y= 0, z= 0, ignoreFace= 0 },
            //right
            new SixIgnoreFace{ x=  1, y= 0, z= 0, ignoreFace= 1 },
            //bottom
            new SixIgnoreFace{ x=  0, y=-1, z= 0, ignoreFace= 2 },
            //Up
            new SixIgnoreFace{ x=  0, y= 1, z= 0, ignoreFace= 3 },
            //back
            new SixIgnoreFace{ x=  0, y= 0, z=-1, ignoreFace= 4 },
            //forward
            new SixIgnoreFace{ x=  0, y= 0, z= 1, ignoreFace= 5 },
        };

        private Dictionary<string, bool> _hashTable;

        #region Renderer
        
        
        #endregion

        #region RT

        /// <summary>
        /// 用于检测某个voxel面忽略
        /// 使用前和使用后清空
        /// 这个不能在多线程环境下使用
        /// </summary>
        private readonly List<int> _ignoreFace = new List<int>(6);
        
        /// <summary>
        /// 临时存储一波顶点
        /// 使用前和使用后清空
        /// 这个不能在多线程环境下使用
        /// </summary>
        private readonly List<Vector3> _voxelVertices = new List<Vector3>();

        private readonly List<Vector3> _normals = new List<Vector3>(6);
        
        #endregion

        public void DrawMesh(List<Vector3> vertex,List<int> tri,List<Color> colors,List<Vector3> normals,int idx)
        {
            var gameObj = Object.Instantiate(renderer, renderer.transform.parent, true);
            gameObj.transform.localScale = Vector3.one;
            
            var mesh = new Mesh {name = "Mesh" + idx};
            mesh.SetVertices(vertex);
            mesh.SetTriangles(tri,0);
            mesh.SetColors(colors);
            mesh.SetNormals(normals);
            var meshFilter = gameObj.GetComponent<MeshFilter>();
            meshFilter.mesh = mesh;
        }
        
        public void Init(TVoxelData voxelData, VoxelParam param)
        {
            _voxelData = voxelData;
            _voxelParam = param;
            
            Build();
        }

        private void Build()
        {
            // 邻接判定表
            _hashTable = CreateHashTable(_voxelData.voxel);

            var offsetX = (_voxelData.size.x - 1) * -0.5f;
            var offsetY = (_voxelData.size.y - 1) * -0.5f;
            var offsetZ = (_voxelData.size.z - 1) * -0.5f;
            var matrix = new Matrix4x4();
            matrix.SetTRS(new Vector3(offsetX,offsetY,offsetZ),Quaternion.identity, Vector3.one );
            var offset = new Vector3(offsetX, offsetY, offsetZ);

            var total = _voxelData.voxel.Count;
            
            //一次渲染一千个块
            var count = total / 1000;
            for (var i = 0; i <= count; i++)
            {
                var start = i * 1000;
                var end = start + 1000;
                if (end > total) end = total;
                
                var vertex = new List<Vector3>(end - start);
                var tri = new List<int>(end - start);
                var colors = new List<Color>(end - start);
                var normals = new List<Vector3>();
                for (var j = start; j < end; j++)
                {
                    CreateVoxGeometry(_voxelData.voxel[j],offset,vertex,tri,colors,normals);
                }
                
                DrawMesh(vertex,tri,colors,normals,i);
            }
        }

        /// <summary>
        /// 生成一个体素的6个面的渲染信息
        /// </summary>
        private void CreateVoxGeometry(VoxelStruct voxel,Vector3 offset,
            ICollection<Vector3> vertex,ICollection<int> tri,ICollection<Color> colors,ICollection<Vector3> normals)
        {
            //查找相邻的voxel，存在时忽略面
            _ignoreFace.Clear();
            if (_voxelParam.optimizeFaces)
            {
                for (var i = 0; i < _six.Length; i++)
                {
                    var s = _six[i];
                    if (_hashTable.ContainsKey(Hash(voxel.x + s.x , voxel.y + s.y,voxel.z + s.z)))
                    {
                        _ignoreFace.Add(s.ignoreFace);
                    }
                }
            }
            // 6方向全部相邻时返回null
            if (_ignoreFace.Count == 6)
            {
                _ignoreFace.Clear();
                return;
            }
            
            // 顶点数据,数组
            _voxelVertices.Clear();
            for (var i = 0; i < _voxVerticesSource.Length; i++)
            {
                _voxelVertices.Add(_voxVerticesSource[i]*0.5f + new Vector3(voxel.x,voxel.y,voxel.z) + offset);
            }
            
            // 顶点色 读取
            var c = _voxelData.palette[voxel.colorIndex];
            var color = new Color(c.r,c.g,c.b,c.a)/255f;
            
            //读取UV
//            for (var i = 0; i < _voxFacesSource.Length; i++)
//            {
////                    var uv = new THREE.Vector2((voxel.colorIndex + 0.5) / 256, 0.5);
////                    vox.faceVertexUvs[0].push([uv, uv, uv], [uv, uv, uv]);
//            }

            //计算6个面的法线
            for (var i = 0; i < 6; i++)
            {
                var faceVertex = _voxFacesSource[i];
                var l1 = _voxelVertices[faceVertex.faceA.x] - _voxelVertices[faceVertex.faceA.y];
                var l2 = _voxelVertices[faceVertex.faceA.x] - _voxelVertices[faceVertex.faceA.z];
                
                _normals.Add(Vector3.Cross(l1,l2).normalized);
            }

            //生成可显示的面
            for (var i = 0; i < 6; i++)
            {
                if(_ignoreFace.Contains(i)) continue;
                var faceVertex = _voxFacesSource[i];

                var triIdxStart = vertex.Count;

                //压入6顶点，构成一个面
                vertex.Add(_voxelVertices[faceVertex.faceA.x]);
                vertex.Add(_voxelVertices[faceVertex.faceA.y]);
                vertex.Add(_voxelVertices[faceVertex.faceA.z]);
                vertex.Add(_voxelVertices[faceVertex.faceB.x]);
                vertex.Add(_voxelVertices[faceVertex.faceB.y]);
                vertex.Add(_voxelVertices[faceVertex.faceB.z]);

                //送入三角形数组
                tri.Add(triIdxStart);
                tri.Add(triIdxStart+1);
                tri.Add(triIdxStart+2);
                tri.Add(triIdxStart+3);
                tri.Add(triIdxStart+4);
                tri.Add(triIdxStart+5);
                
                //color
                colors.Add(color);
                colors.Add(color);
                colors.Add(color);
                colors.Add(color);
                colors.Add(color);
                colors.Add(color);

                //计算面体素的面的法线
//                var normal = new Vector3(_six[i].x,_six[i].y,_six[i].z);
//                normal = normal.normalized;
                //压入法线信息
                normals.Add(_normals[i]);
                normals.Add(_normals[i]);
                normals.Add(_normals[i]);
                normals.Add(_normals[i]);
                normals.Add(_normals[i]);
                normals.Add(_normals[i]);
            }
            
        }
        
        private static string Hash(int x,int y,int z)
        {
            return "x" + x + "y" + y + "z" + z;
        }

        private Dictionary<string, bool> CreateHashTable(List<VoxelStruct> voxel)
        {
            var ret = new Dictionary<string,bool>();
            voxel.ForEach(v => ret.Add(Hash(v.x, v.y, v.z), true));

            return ret;
        }

        #region 查找表结构数据

        /// <summary>
        /// TODO:替换为
        /// </summary>
        private struct VoxFaceStruct
        {
            public VoxFaceAB faceA;

            public VoxFaceAB faceB;
        }
        
        private struct VoxFaceAB
        {
            public int x;
            public int y;
            public int z;
            public Color color;

            public VoxFaceAB(int _x, int _y, int _z)
            {
                x = _x;
                y = _y;
                z = _z;
                color = Color.clear;
            }
        }
        
        /// <summary>
        /// 体素一个面的渲染信息
        /// UV或者顶点颜色、顶点坐标、法线方向
        /// </summary>
        private struct VoxelFaceRenderer
        {
            public bool isVertexColor;

            //isVertexColor为true这里有值
            public Color vertexColor;

            //避免麻烦，暂时使用6顶点
            public Vector3 vertex0;
            public Vector3 vertex1;
            public Vector3 vertex2;
            public Vector3 vertex3;
            public Vector3 vertex4;
            public Vector3 vertex5;

            //isVertexColor为false这里有值
            public Vector2 uv0;
            public Vector2 uv1;
            public Vector2 uv2;
            public Vector2 uv3;

            public Vector3 normal;
        }

        private struct SixIgnoreFace
        {
            public int x;
            public int y;
            public int z;
            public int ignoreFace;
        }
        #endregion
    }

    public struct VoxelParam
    {
        public int voxelSize;

        public bool vertexColor;

        /// <summary>
        /// 面优化
        /// </summary>
        public bool optimizeFaces;

        /// <summary>
        /// 锚点定位至下方
        /// </summary>
        public bool originToBottom;
    }
    
}